package Advanced;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

import demo07Package.demo07Person;

public class demo07Map集合 {

	public static void main(String[] args) {
//		map();
//		mapErgodic();
//		hashMapCustom();
//		linkedHashMap();
//		hashtable();
//		mapPractice();
//		collection_of();
		douDiZhu();
		
	}
	public static void map() {
		/* java.util.Map<K,V>集合
		 * Map集合的特点：
		 * 		1、Map集合是一个双列集合，一个元素包含两个值(一个key，一个value)
		 * 		2、Map集合中的元素，key和value的数据类型可以相同，也可以不同
		 * 		3、Map集合中的元素，key是不允许重复的，而value是可以重复的
		 * 		4、Map集合中的元素，key和value是一一对应的
		 * java.util.HashMap<K,V> 集合 implements Map<K,V>接口
		 * HashMap集合的特点：
		 * 		1、HashMap集合底层是哈希表：查询的速度特别的快
		 * 		2、HashMap集合是一个无序的集合，存储元素和取出元素的顺序有可能不一致
		 * java.util.LinkedHashMap<K,V> 集合 extends HashMap<K,V> 集合 
		 * LinkedHashMap的特点：
		 * 		1、LinkedHashMap集合底层是哈希表 + 链表(保证迭代的顺序)
		 * 		2、LinkedHashMap集合是一个有序的集合，存储元素和取出元素的顺序是一致的
		 * 
		 * public V put(K key,V value)：把指定的键与指定的值添加到Map集合中
		 * 		返回值V：
		 * 			存储键值对的时候，key不重复，返回值V是null
		 * 			存储键值对的时候，key重复，会使用新的value替换Map中重复的value，返回被替换的value值
		 * public V remove(Object key)：把指定的键所对应的键对值元素，在Map集合中删除，返回被删除的元素
		 * 		返回值V：
		 * 			key存在，V返回被删除的值
		 * 			key不存在，V返回null		
		 * public V get(Object key)：根据指定的键，在Map集合中获取对应的值
		 * 		返回值V：
		 * 			key存在，返回对应的value值
		 * 			key不存在，返回null	
		 * boolean containsKey(Object key)：判断集合中是否包含指定的键
		 * */
		//添加元素
		Map<String,String> map = new HashMap<String,String>();
		String v1 = map.put("李晨:","范冰冰1");
		System.out.println("v1:" + v1);
		
		String v2 = map.put("李晨:","范冰冰2");
		System.out.println("v2:" + v2);
		System.out.println(map);
		
		map.put("冷锋","龙小云");
		map.put("杨过","小龙女");
		map.put("尹志平","小龙女");
		System.out.println(map);
		System.out.println("====================================");
		
		//删除元素
		Map<String,Integer> map1 = new HashMap<String, Integer>();
		map1.put("赵丽颖",168);
		map1.put("杨颖",165);
		map1.put("林志玲",178);
		System.out.println(map1);
		
		Integer v3 = map1.remove("林志玲");
		System.out.println(v3);
		System.out.println(map1);
		
		Integer v4 = map1.remove("林志颖");
		System.out.println(v4);
		System.out.println("===========================================");
		
		//获取元素
		Map<String,Integer> map2 = new HashMap<String, Integer>();
		map2.put("赵丽颖",168);
		map2.put("杨颖",165);
		map2.put("林志玲",178);
		
		Integer v5 = map2.get("杨颖");
		System.out.println(v5);
		
		Integer v6 = map2.get("迪丽热巴");
		System.out.println(v6);
		System.out.println("==============================================");
		
		//判断是否包含对应的键
		Map<String,Integer> map3 = new HashMap<String, Integer>();
		map3.put("赵丽颖",168);
		map3.put("杨颖",165);
		map3.put("林志玲",178);
		
		boolean b1 = map3.containsKey("赵丽颖");
		System.out.println(b1);
		
		boolean b2 = map3.containsKey("赵颖");
		System.out.println(b2);
	}
	public static void mapErgodic() {
		/* Map集合的第一种遍历方式：通过键找值的方式
		 * 实现步骤：
		 * 		1、使用Map集合中的keySet()方法，把所有的key取出来存储到一个Set集合中
		 * 		2、遍历Set集合，获取Map集合中的每一个key
		 * 		3、通过Map集合中的get()方法找到value
		 * Map集合的第二种遍历方式：使用Entry对象遍历
		 * 		Set<map.Entry<K,V>> entrySet() 返回此映射中包含的映射关系的set视图
		 * 实现步骤：
		 * 		1、使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来，存储到一个Set集合中
		 * 		2、遍历Set集合，获取每一个Entry对象
		 * 		3、使用Entry对象中的方法getKey()和getValue()获取键与值
		 * */
		Map<String,Integer> map = new HashMap<String, Integer>();
		map.put("赵丽颖",168);
		map.put("杨颖",165);
		map.put("林志玲",178);
		
		Set<String> set = map.keySet();
		Iterator<String> it = set.iterator();
		while(it.hasNext()) {
			System.out.println(map.get(it.next()));
		}
		
		Set<Map.Entry<String, Integer>> set1 = map.entrySet();
		Iterator<Map.Entry<String,Integer>> it1 = set1.iterator();
		while(it1.hasNext()) {
			Map.Entry<String,Integer> entry = it1.next();
			String key = entry.getKey();
			Integer value = entry.getValue();
			System.out.println("key: " + key + "   value: " + value);
		}
		System.out.println("============================");
		
		for(Map.Entry<String,Integer> entry : set1) {
			String key = entry.getKey();
			Integer value = entry.getValue();
			System.out.println("key: " + key + "   value: " + value);
		}
		
	}
	public static void hashMapCustom() {
		/* HashMap存储自定义类型
		 * Map集合保证key是唯一的：
		 * 		作为key的元素，必须重写hasCode和equals方法，以保证key唯一
		 * */
		HashMap<String, demo07Person> map = new HashMap<>();
		map.put("北京",new demo07Person("张三",18));
		map.put("上海",new demo07Person("李四",19));
		map.put("广州",new demo07Person("王五",20));
		map.put("北京",new demo07Person("赵六",18));
		
		Set<Map.Entry<String,demo07Person>> set = map.entrySet();
		for(Map.Entry<String,demo07Person> entry : set) {
			String city = entry.getKey();
			demo07Person p = entry.getValue();
			System.out.println(city + "----->" + p);
		}
		System.out.println("================================");
		
		HashMap<demo07Person,String> map1 = new HashMap<>();
		map1.put(new demo07Person("女王",18),"英国");
		map1.put(new demo07Person("秦始皇",88),"秦国");
		map1.put(new demo07Person("普京",30),"俄罗斯");
		map1.put(new demo07Person("女王",18),"毛里求斯");
		
		Set<demo07Person> set1 = map1.keySet(); 
		for(demo07Person p : set1) {
			System.out.println(p);
			System.out.println(map1.get(p));
		}
	}
	public static void linkedHashMap() {
		/* java.util.LinkedHashMap<K,V> extends HashMap<K,V>
		 * Map接口的哈希表和连接链表实现，具有可预知的迭代顺序
		 * 底层原理：
		 * 		哈希表 + 链表
		 * */
		LinkedHashMap<String,String> linked = new LinkedHashMap<String, String>();
		linked.put("a","a");
		linked.put("c","c");
		linked.put("b","b");
		linked.put("a","c");
		System.out.println(linked);
		
	}
	public static void hashtable() {
		/* java.util.Hashtable<K,V>集合 implements Map<K,V>接口
		 * Hashtable：底层也是一个哈希表，是一个线程安全的集合，是单线程的集合，速度慢
		 * HashMap：底层也是一个哈希表，是一个线程不安全的集合，是多线程的集合，速度快
		 * 
		 * HashMap(之前学的所有集合)：可以存储null值null键
		 * Hashtable：不能存储null值null键
		 * 
		 * Hashtable集合是很早的集合，后来被新的集合替代了
		 * 不过它的子类Properties很常用，是一个唯一和IO流相结合的集合
		 * */
		Hashtable<String, String> table = new Hashtable<String, String>();
		table.put(null,"a");
		table.put("a",null);
		table.put(null,null);
		System.out.println(table);
	}
	public static void mapPractice() {
		//需求：计算一个字符串中每个字符出现的次数  
		System.out.println("请输入一个字符串：");
		Scanner sc = new Scanner(System.in);
		String input = sc.next();
		sc.close();
		//创建一个HashMap<Character,Integer>存储每个字符出现的次数
		HashMap<Character, Integer> map = new HashMap<Character, Integer>();
		char[] ch = input.toCharArray();
		//解法1
//		for(int i = 0;i < ch.length;i++) {
//			if(map.get(ch[i]) == null) {
//				map.put(ch[i],1);
//			}else {
//				Integer num = map.get(ch[i]);
//				num++;
//				map.put(ch[i],num);
//			}
//		}
		//解法2
		for(int i = 0;i < ch.length;i++) {
			if(!map.containsKey(ch[i])) {
				map.put(ch[i],1);
			}else {
				Integer num = map.get(ch[i]);
				num++;
				map.put(ch[i],num);
			}
		}
		System.out.println(map);
	}
	public static void collection_of() {
		/* JDK9的新特性：
		 * 		List,Set,Map接口：增加了一个新的静态方法of，可以给集合一次性添加多个元素
		 * 		static<E> List<E> of (E...elements)
		 * 使用前提：
		 * 		当集合中存储元素的个数已经确定了，不在改变时使用
		 * 注意：
		 * 		1、of方法只适用于List,Set,Map接口，不适用于接口的实现类
		 * 		2、of方法的返回值是一个不能改变的集合，不能再使用add/put方法添加元素了，会抛出异常
		 * 		3、Set接口和Map接口在调用of方法的时候，不能有重复的元素会抛出异常
		 * */
		List<String> list = List.of("a","b","c","d","a");
		System.out.println(list);
		
		Set<String> set = Set.of("a","b","c","d");
		System.out.println(set);
		
		Map<String,Integer> map = Map.of("张三",12,"李四",22,"王五",21);
		System.out.println(map);
	}
	public static void douDiZhu() {
		//准备牌
		Map<Integer,String> poker = new LinkedHashMap<Integer, String>();
		List<Integer> index = new ArrayList<Integer>();
		int num = 0;
		List<String> decor = List.of("♥","♠","♣","♦");
		List<String> nums = List.of("3","4","5","6","7","8","9","10","J","Q","K","A","2");
		for(int i = 0;i < nums.size();i++) {
			for(int j = 0;j < decor.size();j++) {
				String str = decor.get(j) + nums.get(i);  
				poker.put(num,str);
				index.add(num);
				num++;
			}
		}
		poker.put(num,"小王");
		index.add(num);
		num++;
		poker.put(num,"大王");
		index.add(num);
		num++;
		
		//洗牌
		Collections.shuffle(index);
		
		//发牌
		ArrayList<Integer> list01 = new ArrayList<Integer>();
		ArrayList<Integer> list02 = new ArrayList<Integer>();
		ArrayList<Integer> list03 = new ArrayList<Integer>();
		ArrayList<Integer> list04 = new ArrayList<Integer>();
		for(int i = 0;i < index.size();i++) {
			int a = index.get(i);
			if(i >= 51) {
				list04.add(a);
			}else if(a % 3 == 0) {
				list01.add(a);
			}else if (a % 3 == 1) {
				list02.add(a);
			}else if (a % 3 == 2) {
				list03.add(a);
			}
		}
		
		//理牌
		Collections.sort(list01);
		Collections.sort(list02);
		Collections.sort(list03);
		Collections.sort(list04);
		
		//看牌
		System.out.print("刘青云：");
		for(int i : list01) {
			System.out.print(poker.get(i)+" ");
		}
		System.out.println();
		
		System.out.print("王诗宁：");
		for(int i : list02) {
			System.out.print(poker.get(i)+" ");
		}
		System.out.println();
		
		System.out.print("大傻逼：");
		for(int i : list03) {
			System.out.print(poker.get(i)+" ");
		}
		System.out.println();
		
		System.out.print("地主牌：");
		for(int i : list04) {
			System.out.print(poker.get(i)+" ");
		}
		System.out.println();
	}
}
